package com.cencat.merchant.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cencat.merchant.entity.Driver;
import com.cencat.merchant.dto.DriverQueryDTO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * 司机管理Mapper接口
 * 提供司机数据的增删改查、统计分析、智能匹配等数据访问功能
 * 
 * @author cencat
 * @version 1.0
 * @since 2025-01-20
 */
@Mapper
public interface DriverMapper extends BaseMapper<Driver> {

    /**
     * 分页查询司机列表
     * 
     * @param page 分页参数
     * @param queryDTO 查询条件
     * @return 司机分页数据
     */
    Page<Driver> selectDriverPage(Page<Driver> page, @Param("query") DriverQueryDTO queryDTO);

    /**
     * 批量更新司机状态
     * 
     * @param ids 司机ID列表
     * @param status 新状态
     * @return 更新记录数
     */
    @Update("<script>" +
            "UPDATE driver SET status = #{status}, update_time = NOW() " +
            "WHERE id IN " +
            "<foreach collection='ids' item='id' open='(' separator=',' close=')'>" +
            "#{id}" +
            "</foreach>" +
            "</script>")
    int batchUpdateStatus(@Param("ids") List<Long> ids, @Param("status") String status);

    /**
     * 批量更新司机信用分数
     * 
     * @param ids 司机ID列表
     * @param creditScore 新信用分数
     * @return 更新记录数
     */
    @Update("<script>" +
            "UPDATE driver SET credit_score = #{creditScore}, update_time = NOW() " +
            "WHERE id IN " +
            "<foreach collection='ids' item='id' open='(' separator=',' close=')'>" +
            "#{id}" +
            "</foreach>" +
            "</script>")
    int batchUpdateCreditScore(@Param("ids") List<Long> ids, @Param("creditScore") BigDecimal creditScore);

    /**
     * 批量更新司机位置信息
     * 
     * @param ids 司机ID列表
     * @param latitude 纬度
     * @param longitude 经度
     * @return 更新记录数
     */
    @Update("<script>" +
            "UPDATE driver SET latitude = #{latitude}, longitude = #{longitude}, update_time = NOW() " +
            "WHERE id IN " +
            "<foreach collection='ids' item='id' open='(' separator=',' close=')'>" +
            "#{id}" +
            "</foreach>" +
            "</script>")
    int batchUpdateLocation(@Param("ids") List<Long> ids, @Param("latitude") BigDecimal latitude, @Param("longitude") BigDecimal longitude);

    /**
     * 根据状态统计司机数量
     * 
     * @param status 司机状态
     * @return 司机数量
     */
    @Select("SELECT COUNT(*) FROM driver WHERE status = #{status}")
    Long countByStatus(@Param("status") String status);

    /**
     * 根据车辆类型统计司机数量
     * 
     * @param vehicleType 车辆类型
     * @return 司机数量
     */
    @Select("SELECT COUNT(*) FROM driver WHERE vehicle_type = #{vehicleType}")
    Long countByVehicleType(@Param("vehicleType") String vehicleType);

    /**
     * 计算平均信用分数
     * 
     * @return 平均信用分数
     */
    @Select("SELECT AVG(credit_score) FROM driver WHERE status = 'ACTIVE'")
    BigDecimal calculateAverageCreditScore();

    /**
     * 查询在线司机列表
     * 
     * @param limit 限制数量
     * @return 在线司机列表
     */
    @Select("SELECT * FROM driver WHERE status = 'ONLINE' ORDER BY update_time DESC LIMIT #{limit}")
    List<Driver> selectOnlineDrivers(@Param("limit") Integer limit);

    /**
     * 查询离线司机列表
     * 
     * @param limit 限制数量
     * @return 离线司机列表
     */
    @Select("SELECT * FROM driver WHERE status = 'OFFLINE' ORDER BY update_time DESC LIMIT #{limit}")
    List<Driver> selectOfflineDrivers(@Param("limit") Integer limit);

    /**
     * 查询忙碌司机列表
     * 
     * @param limit 限制数量
     * @return 忙碌司机列表
     */
    @Select("SELECT * FROM driver WHERE status = 'BUSY' ORDER BY update_time DESC LIMIT #{limit}")
    List<Driver> selectBusyDrivers(@Param("limit") Integer limit);

    /**
     * 查询休息司机列表
     * 
     * @param limit 限制数量
     * @return 休息司机列表
     */
    @Select("SELECT * FROM driver WHERE status = 'REST' ORDER BY update_time DESC LIMIT #{limit}")
    List<Driver> selectRestDrivers(@Param("limit") Integer limit);

    /**
     * 根据车辆类型查询司机列表
     * 
     * @param vehicleType 车辆类型
     * @param status 司机状态
     * @param limit 限制数量
     * @return 司机列表
     */
    @Select("<script>" +
            "SELECT * FROM driver WHERE vehicle_type = #{vehicleType} " +
            "<if test='status != null and status != \"\">" +
            "AND status = #{status} " +
            "</if>" +
            "ORDER BY update_time DESC " +
            "<if test='limit != null'>" +
            "LIMIT #{limit}" +
            "</if>" +
            "</script>")
    List<Driver> selectDriversByVehicleType(@Param("vehicleType") String vehicleType, @Param("status") String status, @Param("limit") Integer limit);

    /**
     * 根据信用分数范围查询司机列表
     * 
     * @param minScore 最小信用分数
     * @param maxScore 最大信用分数
     * @param limit 限制数量
     * @return 司机列表
     */
    @Select("SELECT * FROM driver WHERE credit_score BETWEEN #{minScore} AND #{maxScore} " +
            "ORDER BY credit_score DESC LIMIT #{limit}")
    List<Driver> selectDriversByCreditScore(@Param("minScore") BigDecimal minScore, @Param("maxScore") BigDecimal maxScore, @Param("limit") Integer limit);

    /**
     * 根据注册时间范围查询司机列表
     * 
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param limit 限制数量
     * @return 司机列表
     */
    @Select("SELECT * FROM driver WHERE create_time BETWEEN #{startTime} AND #{endTime} " +
            "ORDER BY create_time DESC LIMIT #{limit}")
    List<Driver> selectDriversByRegistrationTime(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime, @Param("limit") Integer limit);

    /**
     * 根据最后活跃时间查询司机列表
     * 
     * @param lastActiveTime 最后活跃时间
     * @param status 司机状态
     * @param limit 限制数量
     * @return 司机列表
     */
    @Select("<script>" +
            "SELECT * FROM driver WHERE last_active_time >= #{lastActiveTime} " +
            "<if test='status != null and status != \"\">" +
            "AND status = #{status} " +
            "</if>" +
            "ORDER BY last_active_time DESC " +
            "<if test='limit != null'>" +
            "LIMIT #{limit}" +
            "</if>" +
            "</script>")
    List<Driver> selectDriversByLastActiveTime(@Param("lastActiveTime") LocalDateTime lastActiveTime, @Param("status") String status, @Param("limit") Integer limit);

    /**
     * 根据位置范围查询附近司机
     * 
     * @param latitude 纬度
     * @param longitude 经度
     * @param radius 半径（公里）
     * @param status 司机状态
     * @param limit 限制数量
     * @return 附近司机列表
     */
    @Select("<script>" +
            "SELECT *, " +
            "(6371 * acos(cos(radians(#{latitude})) * cos(radians(latitude)) * " +
            "cos(radians(longitude) - radians(#{longitude})) + " +
            "sin(radians(#{latitude})) * sin(radians(latitude)))) AS distance " +
            "FROM driver " +
            "WHERE latitude IS NOT NULL AND longitude IS NOT NULL " +
            "<if test='status != null and status != \"\">" +
            "AND status = #{status} " +
            "</if>" +
            "HAVING distance <= #{radius} " +
            "ORDER BY distance ASC " +
            "<if test='limit != null'>" +
            "LIMIT #{limit}" +
            "</if>" +
            "</script>")
    List<Driver> selectNearbyDrivers(@Param("latitude") BigDecimal latitude, @Param("longitude") BigDecimal longitude, @Param("radius") Double radius, @Param("status") String status, @Param("limit") Integer limit);

    /**
     * 智能匹配司机
     * 
     * @param vehicleType 车辆类型
     * @param minCreditScore 最小信用分数
     * @param latitude 纬度
     * @param longitude 经度
     * @param radius 半径（公里）
     * @param limit 限制数量
     * @return 匹配的司机列表
     */
    @Select("<script>" +
            "SELECT *, " +
            "(6371 * acos(cos(radians(#{latitude})) * cos(radians(latitude)) * " +
            "cos(radians(longitude) - radians(#{longitude})) + " +
            "sin(radians(#{latitude})) * sin(radians(latitude)))) AS distance " +
            "FROM driver " +
            "WHERE status = 'ONLINE' " +
            "AND vehicle_type = #{vehicleType} " +
            "AND credit_score >= #{minCreditScore} " +
            "AND latitude IS NOT NULL AND longitude IS NOT NULL " +
            "HAVING distance <= #{radius} " +
            "ORDER BY credit_score DESC, distance ASC " +
            "<if test='limit != null'>" +
            "LIMIT #{limit}" +
            "</if>" +
            "</script>")
    List<Driver> selectMatchedDrivers(@Param("vehicleType") String vehicleType, @Param("minCreditScore") BigDecimal minCreditScore, @Param("latitude") BigDecimal latitude, @Param("longitude") BigDecimal longitude, @Param("radius") Double radius, @Param("limit") Integer limit);

    /**
     * 检查司机手机号是否存在
     * 
     * @param phone 手机号
     * @param excludeId 排除的司机ID
     * @return 存在数量
     */
    @Select("<script>" +
            "SELECT COUNT(*) FROM driver WHERE phone = #{phone} " +
            "<if test='excludeId != null'>" +
            "AND id != #{excludeId}" +
            "</if>" +
            "</script>")
    int existsByPhone(@Param("phone") String phone, @Param("excludeId") Long excludeId);

    /**
     * 检查司机身份证号是否存在
     * 
     * @param idCard 身份证号
     * @param excludeId 排除的司机ID
     * @return 存在数量
     */
    @Select("<script>" +
            "SELECT COUNT(*) FROM driver WHERE id_card = #{idCard} " +
            "<if test='excludeId != null'>" +
            "AND id != #{excludeId}" +
            "</if>" +
            "</script>")
    int existsByIdCard(@Param("idCard") String idCard, @Param("excludeId") Long excludeId);

    /**
     * 检查司机驾驶证号是否存在
     * 
     * @param licenseNo 驾驶证号
     * @param excludeId 排除的司机ID
     * @return 存在数量
     */
    @Select("<script>" +
            "SELECT COUNT(*) FROM driver WHERE license_no = #{licenseNo} " +
            "<if test='excludeId != null'>" +
            "AND id != #{excludeId}" +
            "</if>" +
            "</script>")
    int existsByLicenseNo(@Param("licenseNo") String licenseNo, @Param("excludeId") Long excludeId);

    /**
     * 搜索司机
     * 
     * @param keyword 关键词
     * @param searchType 搜索类型
     * @param limit 限制数量
     * @return 司机列表
     */
    @Select("<script>" +
            "SELECT * FROM driver WHERE 1=1 " +
            "<choose>" +
            "<when test='searchType == \"name\"'>" +
            "AND name LIKE CONCAT('%', #{keyword}, '%') " +
            "</when>" +
            "<when test='searchType == \"phone\"'>" +
            "AND phone LIKE CONCAT('%', #{keyword}, '%') " +
            "</when>" +
            "<when test='searchType == \"license_no\"'>" +
            "AND license_no LIKE CONCAT('%', #{keyword}, '%') " +
            "</when>" +
            "<otherwise>" +
            "AND (name LIKE CONCAT('%', #{keyword}, '%') " +
            "OR phone LIKE CONCAT('%', #{keyword}, '%') " +
            "OR license_no LIKE CONCAT('%', #{keyword}, '%')) " +
            "</otherwise>" +
            "</choose>" +
            "ORDER BY update_time DESC " +
            "<if test='limit != null'>" +
            "LIMIT #{limit}" +
            "</if>" +
            "</script>")
    List<Driver> searchDrivers(@Param("keyword") String keyword, @Param("searchType") String searchType, @Param("limit") Integer limit);

    /**
     * 查询司机列表（用于导出）
     * 
     * @param queryDTO 查询条件
     * @return 司机列表
     */
    List<Driver> selectDriverList(@Param("query") DriverQueryDTO queryDTO);

    /**
     * 计算指定时间范围内的司机数量
     * 
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param status 司机状态
     * @return 司机数量
     */
    @Select("<script>" +
            "SELECT COUNT(*) FROM driver " +
            "WHERE create_time BETWEEN #{startTime} AND #{endTime} " +
            "<if test='status != null and status != \"\">" +
            "AND status = #{status}" +
            "</if>" +
            "</script>")
    Integer calculateDriverCount(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime, @Param("status") String status);

    /**
     * 计算指定时间范围内的平均信用分数
     * 
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 平均信用分数
     */
    @Select("SELECT AVG(credit_score) FROM driver WHERE create_time BETWEEN #{startTime} AND #{endTime}")
    Double calculateAverageCreditScoreByTime(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 获取司机趋势数据
     * 
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param trendType 趋势类型
     * @return 趋势数据
     */
    List<Map<String, Object>> selectDriverTrends(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime, @Param("trendType") String trendType);

    /**
     * 获取司机排行榜
     * 
     * @param rankType 排行类型
     * @param limit 限制数量
     * @return 排行榜数据
     */
    List<Map<String, Object>> selectDriverRanking(@Param("rankType") String rankType, @Param("limit") Integer limit);

    /**
     * 获取司机分布数据
     * 
     * @param distributionType 分布类型
     * @return 分布数据
     */
    List<Map<String, Object>> selectDriverDistribution(@Param("distributionType") String distributionType);

    /**
     * 更新司机最后活跃时间
     * 
     * @param driverId 司机ID
     * @param lastActiveTime 最后活跃时间
     * @return 更新记录数
     */
    @Update("UPDATE driver SET last_active_time = #{lastActiveTime}, update_time = NOW() WHERE id = #{driverId}")
    int updateLastActiveTime(@Param("driverId") Long driverId, @Param("lastActiveTime") LocalDateTime lastActiveTime);

    /**
     * 更新司机位置
     * 
     * @param driverId 司机ID
     * @param latitude 纬度
     * @param longitude 经度
     * @return 更新记录数
     */
    @Update("UPDATE driver SET latitude = #{latitude}, longitude = #{longitude}, update_time = NOW() WHERE id = #{driverId}")
    int updateDriverLocation(@Param("driverId") Long driverId, @Param("latitude") BigDecimal latitude, @Param("longitude") BigDecimal longitude);

    /**
     * 更新司机信用分数
     * 
     * @param driverId 司机ID
     * @param creditScore 信用分数
     * @return 更新记录数
     */
    @Update("UPDATE driver SET credit_score = #{creditScore}, update_time = NOW() WHERE id = #{driverId}")
    int updateDriverCreditScore(@Param("driverId") Long driverId, @Param("creditScore") BigDecimal creditScore);

    /**
     * 批量更新司机在线状态
     * 
     * @param driverIds 司机ID列表
     * @param isOnline 是否在线
     * @return 更新记录数
     */
    @Update("<script>" +
            "UPDATE driver SET status = #{isOnline}, update_time = NOW() " +
            "WHERE id IN " +
            "<foreach collection='driverIds' item='id' open='(' separator=',' close=')'>" +
            "#{id}" +
            "</foreach>" +
            "</script>")
    int batchUpdateOnlineStatus(@Param("driverIds") List<Long> driverIds, @Param("isOnline") String isOnline);

    /**
     * 获取司机工作统计
     * 
     * @param driverId 司机ID
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 工作统计数据
     */
    Map<String, Object> selectDriverWorkStats(@Param("driverId") Long driverId, @Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 获取司机收入统计
     * 
     * @param driverId 司机ID
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 收入统计数据
     */
    Map<String, Object> selectDriverIncomeStats(@Param("driverId") Long driverId, @Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 获取司机评价统计
     * 
     * @param driverId 司机ID
     * @return 评价统计数据
     */
    Map<String, Object> selectDriverRatingStats(@Param("driverId") Long driverId);
}